#ifndef xpack_io_tty
#define xpack_io_tty
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::io_tty::inc
#include"adapter/format_output_stream.hpp"
#include"configure/switch.hpp"
#include"define/base_type.hpp"
#include"interface/can_alloc.hpp"
#include"io/private/tty_key.hpp"
#include"lang/cxx/format.hpp"
#include"lang/cxx.hpp"
#include"macro/xexport.hpp"
#include"meta/is_origin_string.hpp"
#pragma pop_macro("xuser")

namespace mixc::io_tty{
    enum class tty_color_t : u08 {
        black,
        red,
        green,
        yellow,
        blue,
        magenta,
        cyan,
        white,
        gray,
        light_red,
        light_green,
        light_yellow,
        light_blue,
        light_magenta,
        light_cyan,
        light_gray,
    };
}

namespace mixc::io_tty::inc{
    enum read_key_mode_t : u08{
        is_echo         = 0x1,
        is_non_block    = 0x2,
    };

    extern void             print_core(asciis str, uxx length);
    extern void             get_visiable_area_size(uxx * rows, uxx * columns);
    extern void             get_cursor_position(uxx * row, uxx * column);
    extern void             set_cursor_position(uxx x, uxx y);
    extern tty_key          read_key(read_key_mode_t mode);
    extern c08              read_line(ialloc<char> alloc);
    extern c16              read_line(ialloc<char16_t> alloc);
    extern tty_color_t      backcolor();
    extern tty_color_t      forecolor();
    extern bool             cursor_visiable();
    extern void             cursor_visiable(bool value);
    extern void             clear();
    extern void             print_flush();
    extern void             forecolor(tty_color_t value);
    extern void             backcolor(tty_color_t value);
}
namespace mixc::io_tty{
    struct tty_t;

    xstruct(
        xname(tty_t),
        xpubb(inc::format_output_stream<tty_t>)
    )
    private:
        friend inc::format_output_stream<tty_t>;

        void output_text_core(inc::c08 content) const {
            inc::print_core(asciis(content), content->length);
        }

    public:
        xprops()
            xpubget_pubsetx(backcolor, tty_color_t){
                xr { return inc::backcolor(); }
                xw { inc::backcolor(value); }
            };

            xpubget_pubsetx(is_cursor_visiable, bool){
                xr { return inc::cursor_visiable(); }
                xw { inc::cursor_visiable(value); }
            };

            xpubget_pubsetx(forecolor, tty_color_t){
                xr { return inc::forecolor(); }
                xw { inc::forecolor(value); }
            };
        $

        xprops_operator()

    public:
        void clear() const {
            inc::clear();
        }

        void flush() const {
            inc::print_flush();
        }

        inc::tty_key read_key() const {
            return inc::read_key(inc::read_key_mode_t{});
        }

        inc::tty_key read_key(echo_t) const {
            return inc::read_key(inc::is_echo);
        }

        inc::tty_key read_key_non_block() const {
            return inc::read_key(inc::is_non_block);
        }

        inc::tty_key read_key_non_block(echo_t) const {
            return inc::read_key(inc::read_key_mode_t(inc::is_echo | inc::is_non_block));
        }

        inc::c08 read_line(inc::ialloc<char> alloc) const {
            return inc::read_line(alloc);
        }

        inc::c16 read_line(inc::ialloc<char16_t> alloc) const {
            return inc::read_line(alloc);
        }
    $
}

namespace mixc::io_tty::origin{
    using mixc::io_tty::tty_color_t;
    using namespace inc::place_holder;
    inline tty_t tty;
}

#endif

#include"io/private/tty_key.hpp"

xexport_space(mixc::io_tty::origin)